#include "GameGuid.h"
#include <sstream>
#include <iomanip>
#include <random>

namespace PocketSurvival::Engine
{
    union Byte8Data
    {
        char buff[8];
        int64_t int64_value;
        uint64_t uint64_value;
        double double_value;
        struct
        {
            int32_t a;
            int32_t b;
        };

        struct
        {
            int16_t aa;
            int16_t ab;
            int16_t ba;
            int16_t bb;
        };
    };

    GameGuid::GameGuid()
    {
        memset(guidData.buff, 0, sizeof(guidData.buff));
    }
    
    GameGuid::~GameGuid(){}
    GameGuid::GameGuid(const std::string& guidStr)
    {
        fromString(guidStr);
    }

    const GameGuid& GameGuid::GetZeroGuid()
    {
        static GameGuid zeroGuid {0,0};
        return zeroGuid;
    }

    static void reversal2Byte(char * buff)
    {
        char c;
        c = buff[0];
        buff[0] = buff[1];
        buff[1] = c;
    }

    static void reversal4Byte(char * buff)
    {
        char catchData[4];
        catchData[0] = buff[3];
        catchData[1] = buff[2];
        catchData[2] = buff[1];
        catchData[3] = buff[0];
        memcpy(buff, catchData, 4);
    }

    std::string GameGuid::toString() const
    {
        std::stringstream ss;
        ss << std::hex << std::nouppercase << std::setfill('0');
        ss << std::setw(8) << (guidData.a) << '-';
        ss << std::setw(4) << (int16_t)(guidData.b & 0xFFFFU) << '-';
        ss << std::setw(4) << (int16_t)(guidData.b >> 16U) << '-';

        Byte8Data byte8Data;
        byte8Data.int64_value = guidData.cd;

        reversal2Byte(&byte8Data.buff[0]);
        reversal2Byte(&byte8Data.buff[2]);
        reversal4Byte(&byte8Data.buff[4]);
        
        ss << std::setw(4) << byte8Data.aa << '-';
        ss << std::setw(4) << byte8Data.ab;
        ss << std::setw(8) << byte8Data.b;
        return ss.str();
    }

    void GameGuid::createRandom()
    {
        static std::random_device rd;
        static std::uniform_int_distribution<uint64_t> dist(0ULL, 0xFFFFFFFFFFFFFFFFULL);
        guidData.ab = dist(rd);
        guidData.cd = dist(rd);
    }

    void GameGuid::fromString(const std::string& guidStr)
    {
        if(guidStr.length() > 36)
        {
            return;
        }
        char buff[20];
        int32_t buffIndex = 0;
        bool fillHexFlag = false;
        char lastValue;
        for(int32_t index = 0; index < guidStr.length(); index++)
        {
            char c = guidStr[index];
            if(c == '-')
            {
                continue;
            }
            char value = -1;
            if(c >= '0' && c <= '9')
            {
                value = c - '0';
            }
            else if(c >= 'a' && c <= 'f')
            {
                value = c - 'a' + 10;
            }
            else if(c >= 'A' && c <= 'F')
            {
                value = c - 'A' + 10;
            }

            if(value != -1)
            {
                if(fillHexFlag == false)
                {
                    fillHexFlag = true;
                    lastValue = value;
                }
                else
                {
                    fillHexFlag = false;
                    lastValue = (lastValue << 4) | value;
                    buff[buffIndex] = lastValue;
                    buffIndex++;
                }
            }
        }
        guidData.buff[0] = buff[3];
        guidData.buff[1] = buff[2];
        guidData.buff[2] = buff[1];
        guidData.buff[3] = buff[0];

        guidData.buff[4] = buff[5];
        guidData.buff[5] = buff[4];

        guidData.buff[6] = buff[7];
        guidData.buff[7] = buff[6];

        guidData.buff[8] = buff[8];
        guidData.buff[9] = buff[9];
        
        guidData.buff[10] = buff[10];
        guidData.buff[11] = buff[11];
        guidData.buff[12] = buff[12];
        guidData.buff[13] = buff[13];
        guidData.buff[14] = buff[14];
        guidData.buff[15] = buff[15];
    }

}